package club.vann.leetcode.offer.daily;

import java.util.Arrays;

/**
 * <p>难度：Hard</p>
 * <p>题目：地下城游戏</p>
 * <p>描述：一些恶魔抓住了公主（P）并将她关在了地下城的右下角。地下城是由 M x N 个房间组成的二维网格。我们英勇的骑士（K）最初被安置在左上角的房间里，他必须穿过地下城并通过对抗恶魔来拯救公主。
 *
 * 骑士的初始健康点数为一个正整数。如果他的健康点数在某一时刻降至 0 或以下，他会立即死亡。
 *
 * 有些房间由恶魔守卫，因此骑士在进入这些房间时会失去健康点数（若房间里的值为负整数，则表示骑士将损失健康点数）；其他房间要么是空的（房间里的值为 0），要么包含增加骑士健康点数的魔法球（若房间里的值为正整数，则表示骑士将增加健康点数）。
 *
 * 为了尽快到达公主，骑士决定每次只向右或向下移动一步。
 *
 *  
 *
 * 编写一个函数来计算确保骑士能够拯救到公主所需的最低初始健康点数。
 *
 * 例如，考虑到如下布局的地下城，如果骑士遵循最佳路径 右 -> 右 -> 下 -> 下，则骑士的初始健康点数至少为 7。
 *
 * -2 (K)	-3	3
 * -5	-10	1
 * 10	30	-5 (P)
 *  
 *
 * 说明:
 *
 * 骑士的健康点数没有上限。
 *
 * 任何房间都可能对骑士的健康点数造成威胁，也可能增加骑士的健康点数，包括骑士进入的左上角房间以及公主被监禁的右下角房间。
 * 通过次数12,709提交次数29,343
 *
 * 来源：力扣（LeetCode）
 * 链接：https://leetcode-cn.com/problems/dungeon-game
 * 著作权归领扣网络所有。商业转载请联系官方授权，非商业转载请注明出处。</p>
 * Created with IntelliJ IDEA.
 * User: fanyu
 * Date: 2020/7/12
 * Time: 9:50
 * To change this template use File | Settings | File Templates.
 * Description:
 */
public class LeetCode_174 {
    public static void main(String[] args) {
        LeetCode_174 leetCode = new LeetCode_174();

        System.out.println("Resultlt["+TestCase.ANS+"] : " + leetCode.calculateMinimumHP(TestCase.DUNGEON));
        System.out.println("Result["+TestCase.ANS1+"] : " + leetCode.calculateMinimumHP(TestCase.DUNGEON1));
        System.out.println("Result["+TestCase.ANS2+"] : " + leetCode.calculateMinimumHP(TestCase.DUNGEON2));
        System.out.println("Result["+TestCase.ANS3+"] : " + leetCode.calculateMinimumHP(TestCase.DUNGEON3));
    }

    /**
     * 解法一：
     *
     * @param dungeon
     * @return
     */
    private int calculateMinimumHP(int[][] dungeon) {
        int lenY = dungeon.length;
        int lenX = dungeon[0].length;
        int[][] dp = new int[lenY+1][lenX+1];
        for(int n = 0; n <= lenY; n ++) {
            Arrays.fill(dp[n], Integer.MAX_VALUE);
        }
        dp[lenY-1][lenX] = 1;
        dp[lenY][lenX-1] = 1;
        for(int y = lenY-1; y >= 0; y --) {
            for(int x = lenX-1; x >= 0; x --) {
                int minn = Math.min(dp[y + 1][x], dp[y][x + 1]);
                dp[y][x] = Math.max(minn - dungeon[y][x], 1);
            }
        }
        return dp[0][0];
    }

    static class TestCase {
        public static final int ANS = 7;
        public static final int[][] DUNGEON = {{-2,-3,3}, {-5,-10,1}, {10,30,-5}};

        public static final int ANS1 = 1;
        public static final int[][] DUNGEON1 = {{100}};

        public static final int ANS2 = 2;
        public static final int[][] DUNGEON2 = {{-1},{1}};

        public static final int ANS3 = 4;
        public static final int[][] DUNGEON3 = {{-3},{1}};
    }
}
